import {
  createSchemaUtils,
  Experimental_DefaultFormStateBehavior,
  ID_KEY,
  JSON_SCHEMA_DRAFT_2020_12,
  PROPERTIES_KEY,
  REF_KEY,
  RJSFSchema,
  SCHEMA_KEY,
  SchemaUtilsType,
  ValidatorType,
} from '../src';
import getTestValidator from './testUtils/getTestValidator';

describe('createSchemaUtils()', () => {
  const testValidator: ValidatorType = getTestValidator({});
  const rootSchema: RJSFSchema = { type: 'object' };
  const defaultFormStateBehavior: Experimental_DefaultFormStateBehavior = {
    arrayMinItems: { populate: 'requiredOnly' },
  };
  const schemaUtils: SchemaUtilsType = createSchemaUtils(testValidator, rootSchema, defaultFormStateBehavior);

  it('getRootSchema()', () => {
    expect(schemaUtils.getRootSchema()).toEqual(rootSchema);
  });

  it('getValidator()', () => {
    expect(schemaUtils.getValidator()).toBe(testValidator);
  });

  describe('2020-12 schema', () => {
    const rootSchema2020: RJSFSchema = {
      [SCHEMA_KEY]: JSON_SCHEMA_DRAFT_2020_12,
      [ID_KEY]: 'https://example.com/2020-12.json',
      type: 'object',
      $defs: {
        example: {
          type: 'integer',
        },
      },
      [PROPERTIES_KEY]: {
        ref: {
          [REF_KEY]: '#/$defs/example',
        },
      },
    };
    const schemaUtils2020: SchemaUtilsType = createSchemaUtils(testValidator, rootSchema2020, defaultFormStateBehavior);

    it('getRootSchema()', () => {
      expect(schemaUtils2020.getRootSchema()).toEqual({
        ...rootSchema2020,
        [PROPERTIES_KEY]: {
          ref: {
            [REF_KEY]: 'https://example.com/2020-12.json#/$defs/example',
          },
        },
      });
    });
  });

  describe('doesSchemaUtilsDiffer()', () => {
    describe('constructed without defaultFormStateBehavior', () => {
      const schemaUtils: SchemaUtilsType = createSchemaUtils(testValidator, rootSchema);

      it('returns false when not passing defaultFormStateBehavior', () => {
        expect(schemaUtils.doesSchemaUtilsDiffer(testValidator, rootSchema)).toBe(false);
      });
      it('returns true when passing different defaultFormStateBehavior', () => {
        expect(
          schemaUtils.doesSchemaUtilsDiffer(testValidator, rootSchema, { arrayMinItems: { populate: 'requiredOnly' } }),
        ).toBe(true);
      });
    });

    describe('constructed with defaultFormStateBehavior', () => {
      it('returns false when passing same validator, rootSchema, and defaultFormStateBehavior', () => {
        expect(schemaUtils.doesSchemaUtilsDiffer(testValidator, rootSchema, defaultFormStateBehavior)).toBe(false);
      });
      it('returns false when passing falsy validator', () => {
        expect(schemaUtils.doesSchemaUtilsDiffer(null as unknown as ValidatorType, {}, defaultFormStateBehavior)).toBe(
          false,
        );
      });
      it('returns false when passing falsy rootSchema', () => {
        expect(
          schemaUtils.doesSchemaUtilsDiffer(testValidator, null as unknown as RJSFSchema, defaultFormStateBehavior),
        ).toBe(false);
      });
      it('returns true when passing different validator', () => {
        expect(schemaUtils.doesSchemaUtilsDiffer(getTestValidator({}), {}, defaultFormStateBehavior)).toBe(true);
      });
      it('returns true when passing different rootSchema', () => {
        expect(schemaUtils.doesSchemaUtilsDiffer(testValidator, {}, defaultFormStateBehavior)).toBe(true);
      });
      it('returns true when passing different defaultFormStateBehavior', () => {
        expect(
          schemaUtils.doesSchemaUtilsDiffer(testValidator, rootSchema, { arrayMinItems: { populate: 'all' } }),
        ).toBe(true);
      });
    });
  });
  // NOTE: the rest of the functions are tested in the tests defined in the `schema` directory
});
